#include "SamplerJittered.h"
#include <cstdlib>

SamplerJittered::SamplerJittered(int num_samples, FilterType ftype) : Sampler(num_samples, ftype)
{ 
	//divide the area of a pixel into num_samples^2 boxes for each unit of filter area
	delta = 1.0 / base_num_samples;
	num_samples_x = base_num_samples * filter->getSupport();
	num_samples_y = base_num_samples * filter->getSupport();
	//now find the border such that a pixel at border+delta*sample number will fire through the middle
	//of a given sub-pixel
	half_delta = delta / 2.0;
	max_x_change = filter->getSupport() / 2.0;
	max_y_change = filter->getSupport() / 2.0;
	//set up for later equations
	total_samples = num_samples_x * num_samples_y;
}

SamplerJittered::~SamplerJittered()
{};

/*
 * Jitter values should vary from -1 to 1
 * so that they can be easily converted into
 * pixel coordinates
 */
double SamplerJittered::get_jitter()
{
	int some_number = rand();
	//printf("Random number:\t %d\n", some_number);
	double fraction = ((double)some_number / (double)RAND_MAX);
	//printf("Fraction: \t%f\n", fraction);
	double result =  (fraction - 0.5) * 2;
	//printf("Final random number: %f\n", result);
	return result;
}

void SamplerJittered::offsetRay(Ray& ray, int sample_num, double dx, double dy)
{
	//a ray normally fires through the middle of a pixel, or at pixel coordinates
	// 0.5, 0.5. We assume any incoming ray is being fired through that point. We must now find where this ray should fire
	//through for the given sample number
	int sample_y = sample_num / num_samples_y;
	int sample_x = sample_num % num_samples_x;
	//now find where in pixel coordinates the ray should fire. Pixel coordinates should range from -0.5 to 0.5 for single pixel samples,
	//from larger for multi-pixel sampling
	last_pix_coord_x = ((half_delta + delta * sample_x) - max_x_change) + (get_jitter() * half_delta);
	last_pix_coord_y = ((half_delta + delta * sample_y) - max_y_change) + (get_jitter() * half_delta);
	//now find the change in the ray. The change should range from -0.5 to 0.5 for a sample/filter combination that does not
	//sample outside a single pixel. It may range farther for multi-pixel sampling
	last_offset_x = (last_pix_coord_x) * dx;
	last_offset_y = (last_pix_coord_y) * dy;
	//printf("Sample: %d (%d, %d)\n", sample_num, sample_x, sample_y);
	//printf(" Pixel coordinates: \t%f\t%f\n", last_pix_coord_x, last_pix_coord_y);
	//printf(" Change \tx: %f\tChange y: %f\t (deltax: %f\tdeltay: %f)\n", last_offset_x, last_offset_y, dx, dy);
	//printf(" Original ray direction:\t %f %f %f\n", ray.direction().x(), ray.direction().y(), ray.direction().z());
	Vector new_direction = Vector(ray.direction().x() + last_offset_x, ray.direction().y() + last_offset_y, ray.direction().z());
	new_direction.normalize();
	ray = Ray(ray.origin(), new_direction);
}

void SamplerJittered::applyFilter(Color* sample_colors, double* offsets_x, double* offsets_y) const
{ 
	
	double* weights = new double[total_samples];
	filter->getWeights(weights, total_samples, offsets_x, offsets_y);
	for(int i = 0; i < total_samples; i++) {
		sample_colors[i] = sample_colors[i] * weights[i];
	}
}
		
